﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

using SamuelBlanchard.Extenders;
using Techdays2013.Codes.SpeechRecognition;
using Techdays2013.Codes.TextToSpeech;
using System.Diagnostics;
using Windows.Phone.Speech.Recognition;
using System.Windows.Media;
using Windows.Foundation;
using System.Windows.Media.Animation;

namespace Techdays2013
{
    public partial class SpeechRecognitionPage : PhoneApplicationPage
    {
        public SpeechRecognitionPage()
        {
            InitializeComponent();

            this.LayoutRoot.DataContext = this;

            this.Blagues = new List<Blague>();

            this.Blagues.Add(new Blague() { Famille = "Lairbon", IsFils = true, Prenom = "Oussama" });
            this.Blagues.Add(new Blague() { Famille = "Soif", IsFils = true, Prenom = "Roger" });
            this.Blagues.Add(new Blague() { Famille = "La-airdouze", IsFils = true, Prenom = "Igor" });
            this.Blagues.Add(new Blague() { Famille = "Danvozieu", IsFils = false, Prenom = "Julie" });
            this.Blagues.Add(new Blague() { Famille = "Micoton", IsFils = false, Prenom = "Mylène" });
            this.Blagues.Add(new Blague() { Famille = "Tamaire", IsFils = false, Prenom = "Annick" });
            //this.Blagues.Add(new Blague() { Famille = "Stringlété", IsFils = true, Prenom = "Amédé" });
            this.Blagues.Add(new Blague() { Famille = "Ailecon", IsFils = true, Prenom = "Jeff" });
            this.Blagues.Add(new Blague() { Famille = "Covère", IsFils = true, Prenom = "Harry" });
            //this.Blagues.Add(new Blague() { Famille = "Chon", IsFils = true, Prenom = "Denis" });
            this.Blagues.Add(new Blague() { Famille = "Tatouille", IsFils = false, Prenom = "Sarah" });
            this.Blagues.Add(new Blague() { Famille = "Sselatableu", IsFils = false, Prenom = "Déborah" });
            this.Blagues.Add(new Blague() { Famille = "Keunitete", IsFils = false, Prenom = "Jenny" });
            this.Blagues.Add(new Blague() { Famille = "Zeblouse", IsFils = false, Prenom = "Agathe" });
            this.Blagues.Add(new Blague() { Famille = "Manvussa", IsFils = true, Prenom = "Gérard" });

            this.RefreshCurrentBlague();

            this.StoryboardHead.Completed += StoryboardHead_Completed;

            this.Loaded += SpeechRecognitionPage_Loaded;

            this.BackKeyPress += TextToSpeechPage_BackKeyPress;
            this.GridFade.Visibility = System.Windows.Visibility.Visible;

            this.BonhommeBrush = new SolidColorBrush(Colors.Magenta);
        }

        /// <summary>
        /// Listes des blagues
        /// </summary>

        private List<Blague> Blagues = null;

        /// <summary>
        /// Completed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        void StoryboardHead_Completed(object sender, EventArgs e)
        {
            this.TransformHead.TranslateY = 0;
        }

        /// <summary>
        /// Chargement
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        void SpeechRecognitionPage_Loaded(object sender, RoutedEventArgs e)
        {
            this.BonhommeCanvas.IsHitTestVisible = false;

            bool isAssociation = NavigationContext.QueryString.ContainsKey("said");

            if (isAssociation == true)
            {
                this.TextBlockTitle.Text = "Protocole techdays2013 en arrivé !";
                this.TextBlockTitle.FontSize = 70;
                this.Title.Text = "Association d'URI";
                this.StackPanelButtons.Visibility = System.Windows.Visibility.Collapsed;
            }

            this.GridFade.FadeOut( async (s) =>
            {
                s.Visibility = Visibility.Collapsed;

                string text;

                if (isAssociation == false)
                {
                    // par défaut
                    text = "Appuyez sur moi pour commencer";
                }
                else
                {
                    // Lancement par protocole
                    text = NavigationContext.QueryString["said"];
                }

                await this.SpeakBonhomme(text);

                this.BonhommeCanvas.IsHitTestVisible = true;
            });
        }

        /// <summary>
        /// Couleur du Bonhomme
        /// </summary>

        public Brush BonhommeBrush
        {
            get { return (Brush)GetValue(BonhommeBrushProperty); }
            set { SetValue(BonhommeBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for BonhommeBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty BonhommeBrushProperty =
            DependencyProperty.Register("BonhommeBrush", typeof(Brush), typeof(SpeechRecognitionPage), new PropertyMetadata(null));

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        void TextToSpeechPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (NavigationService.CanGoBack == true)
            {
                e.Cancel = true;

                if (this.BonhommeCanvas.IsHitTestVisible == false)
                {
                    return;
                }

                this.GridFade.Visibility = System.Windows.Visibility.Visible;
                this.GridFade.FadeIn((s) => { NavigationService.GoBack(); });
            }
        }

        /// <summary>
        /// Nombre pseudo aléatoire
        /// </summary>

        Random rand = new Random();

        /// <summary>
        /// Reconnaissance avec interface
        /// </summary>

        bool IsRecognitionWithUI = true;

        /// <summary>
        /// Blague
        /// </summary>

        public Blague CurrentBlague
        {
            get { return (Blague)GetValue(CurrentBlagueProperty); }
            set { SetValue(CurrentBlagueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for CurrentBlague.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CurrentBlagueProperty =
            DependencyProperty.Register("CurrentBlague", typeof(Blague), typeof(SpeechRecognitionPage), new PropertyMetadata(null));

        /// <summary>
        /// On tap sur la page
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        async void Bonhomme_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            this.BonhommeCanvas.IsHitTestVisible = false;
            
            // Avec UI
            if (IsRecognitionWithUI == true)
            {
                try
                {
                    // Avec UI
                    var result = await SpeechRecognitionHelper.RecognizeUI(
                        "Donne un prénom pour résoudre la blague !",
                        "Henri !",
                        true,
                        true
                        //,grammars
                        );

                    if (result.ResultStatus == Windows.Phone.Speech.Recognition.SpeechRecognitionUIStatus.Succeeded)
                    {
                        this.ManageRecognitionResult(this.CurrentBlague, result.RecognitionResult);
                    }
                    else
                    {
                        switch (result.ResultStatus)
                        {
                            case SpeechRecognitionUIStatus.Preempted:
                            case SpeechRecognitionUIStatus.Busy:
                                await this.SpeakBonhomme("C'est occupé !");
                                break;

                            case SpeechRecognitionUIStatus.PrivacyPolicyDeclined:
                                await this.SpeakBonhomme("Tu ne veux pas m'aider à retrouver mon prénom ?");
                                break;
                        }
                    }
                }
                catch
                {
                }
                finally
                {
                    this.BonhommeCanvas.IsHitTestVisible = true;
                }
            }
            else
            {
                Blague blague = this.CurrentBlague;

                // Nom gagnant
                var grammars =
                    new List<string>(){ 
                        blague.Prenom         
                        };

                try
                {
                    this.BonhommeBrush = new SolidColorBrush(Colors.Red);

                    var r = await SpeechRecognitionHelper.Recognize(
                        //true
                        false, grammars
                        );

                    this.ManageRecognitionResult(this.CurrentBlague, r);
                }
                catch
                {
                }
                finally
                {
                    this.BonhommeBrush = new SolidColorBrush(Colors.Magenta);
                    this.BonhommeCanvas.IsHitTestVisible = true;
                }
            }
        }

        /// <summary>
        /// Réponse
        /// </summary>
        /// <param name="result"></param>

        private async void ManageRecognitionResult(Blague blague, SpeechRecognitionResult result)
        {
            try
            {
                bool isWinned = this.IsPrenomContainsInResult(blague.Prenom, result.Text);

                if (isWinned == false || result.TextConfidence == SpeechRecognitionConfidence.Rejected)
                {
                    string[] BadResults = new string[]
                    {"Non ce n'est pas ça",
                      "Essaie encore",
                      "euuuuuh certainenement pas",
                      "Nen c'est pas ça !",
                      "Bien sur que non !",
                      "Oui mais non !",
                    };

                    await this.SpeakBonhomme( BadResults[rand.Next(BadResults.Length)] );
                    return;
                }
                else if( result.TextConfidence == SpeechRecognitionConfidence.Low )
                {
                    await this.SpeakBonhomme("Désolé mais je ne suis pas sûr d'avoir compris ta réponse");
                    return;
                }


                await this.SpeakBonhomme( "Gagné!" );

                this.Response(blague);
            }
            catch
            {
            }
        }

        /// <summary>
        /// Reponse
        /// </summary>
        /// <param name="blague"></param>

        private async void Response(Blague blague)
        {
                string pronom = blague.IsFils ? "Il" : "Elle";

                await this.SpeakBonhomme(pronom + " s'appelle " + blague.Prenom + " " + blague.Famille);

                this.RefreshCurrentBlague();
        }

        /// <summary>
        /// Rafraichir la blague
        /// </summary>

        private void RefreshCurrentBlague()
        {
            int index = this.rand.Next( this.Blagues.Count );
            Blague blague = this.Blagues[ index ];

            // Pas deux fois la même vanne
            if (this.CurrentBlague == blague)
            {
                index = (index+1) % this.Blagues.Count;
                blague = this.Blagues[index];
            }

            this.CurrentBlague = blague;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="text"></param>

        private bool IsPrenomContainsInResult(string prenom, string text)
        {
            if (string.IsNullOrWhiteSpace(prenom) == true || string.IsNullOrWhiteSpace(text))
                return false;

            prenom = prenom.ToLower();

                // index de la fin de de l'adjectif
                bool isPresent = text.Split(new char[] { ',','"','\'', ' ', '?', '!', '.' })
                    .Select((p)=>p.ToLower())
                    .Contains(prenom);

                return isPresent;
        }

        /// <summary>
        /// Minivoice
        /// </summary>
        /// <param name="text"></param>

        private IAsyncAction SpeakBonhomme(string text, string cultureInfo = "fr-FR")
        {

            this.StoryboardHead.Stop();

            // Le repeatbehavior (nbr de lettre / 6.8) donne globalement un meilleur résultat que de fermer le storyboard après le Speak (pour les phrases courtes)
            this.StoryboardHead.RepeatBehavior = new System.Windows.Media.Animation.RepeatBehavior((double)text.Length / 6.8);
            this.StoryboardHead.Begin();

            return TextToSpeechHelper.Speak(text, cultureInfo, Windows.Phone.Speech.Synthesis.VoiceGender.Male);
        }

        /// <summary>
        /// UI
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private async void Button_Click_UI(object sender, RoutedEventArgs e)
        {
            this.IsRecognitionWithUI = !this.IsRecognitionWithUI;

            if (this.IsRecognitionWithUI == false)
            {
                this.PictureWindows.Opacity = 0.25;

                await this.SpeakBonhomme("appuyez sur moi puis attendez que je devienne rouge.");
            }
            else
            {
                this.PictureWindows.Opacity = 1;
            }
        }

        /// <summary>
        /// Voice Commande Query
        /// </summary>
        /// <param name="e"></param>

        protected async override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            // Il y a un element !

            if (NavigationContext.QueryString.Any())
            {
                if (e.NavigationMode == NavigationMode.New)
                {
                    if (NavigationContext.QueryString.ContainsKey("voiceCommandName"))
                    {
                        string command = NavigationContext.QueryString["voiceCommandName"];

                        // Plusieurs command possible
                        switch (command)
                        {
                            case "QuiCommandeName" :

                                string speech = NavigationContext.QueryString["reco"].Substring("Techdays2013".Length);

                                await this.SpeakBonhomme(speech);
                                
                                break;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Resultat
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private async void Button_Click_Result(object sender, RoutedEventArgs e)
        {
            await this.SpeakBonhomme("Perdu !");
            this.Response(this.CurrentBlague);
        }
    }
}